package com.hcc.flow.server.service.flowDesign;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.hcc.flow.server.common.constant.Constant;
import com.hcc.flow.server.common.enums.DataStatusType;
import com.hcc.flow.server.common.model.ApiResult;
import com.hcc.flow.server.common.utils.StringUtilsV2;
import com.hcc.flow.server.dao.flowDesign.FlowDesignDao;
import com.hcc.flow.server.dao.flowDesign.FlowDesignTempDao;
import com.hcc.flow.server.model.common.LoginUser;
import com.hcc.flow.server.model.flowDesign.FlowDesign;
import com.hcc.flow.server.model.flowDesign.FlowDesignTemp;
import com.hcc.flow.server.utils.UserUtil;

import net.sf.json.util.JSONUtils;

@Service
public class FlowService {
	
	@Autowired
	private FlowDesignDao flowDao;
	@Autowired
	private FlowDesignTempDao flowTempDao;
	
	@Transactional
	public ApiResult<?> save(FlowDesign flow) {
		LoginUser user = UserUtil.getLoginUser();
		if(StringUtilsV2.isNotBlank(flow.getFlowCode())) {
			FlowDesign codeFlow;
			if(StringUtilsV2.isBlank(flow.getFollowOrgId()))
				codeFlow = flowDao.getByCode(flow.getFlowCode());
			else {
				codeFlow = flowDao.getByCodeAndFollowOrgId(flow.getFlowCode(),flow.getFollowOrgId());
			}
			if(codeFlow != null) {
				if(StringUtilsV2.isBlank(flow.getFlowId())){
					return ApiResult.error("新增流程失败，流程编码已存在，对应流程："+codeFlow.getFlowName());
				}else if(!codeFlow.getFlowId().equals(flow.getFlowId())) {
					return ApiResult.error("更新流程失败，流程编码已存在，对应流程："+codeFlow.getFlowName());
				}
			}
		}
		if(StringUtilsV2.isBlank(flow.getFlowId())) {
			flow.setCreateUserId(user.getUserId());
			/*
			 * if(StringUtilsV2.isNotBlank(flow.getFollowOrgId()) &&
			 * StringUtilsV2.isNotBlank(flow.getFlowType()) &&
			 * StringUtilsV2.isNotBlank(flow.getFlowAttribute())) { List<Flow> list =
			 * flowDao.getByOrgIdAndStatusAndAttribute(flow.getFollowOrgId(),flow.
			 * getFlowType(), Constant.DATA_STATUS_TYPE_NORMAL, flow.getFlowAttribute());
			 * if(list.size() > 0) { //return
			 * ApiResult.error("新增流程失败，该机构已经存在一个启用状态的"+MsgTaskType.getName(flow.getFlowType(
			 * ))+"流程,若想保存，请将之前的流程改为停用状态"); flow.setStatus(DataStatusType.STOP.getCode());
			 * }else { flow.setStatus(DataStatusType.NORMAL.getCode()); } }
			 */
			if(StringUtilsV2.isBlank(flow.getFlowName())) {
				return ApiResult.error("流程名称不能为空");
			}
			if(StringUtilsV2.isBlank(flow.getFollowOrgId())) {
				return ApiResult.error("流程归属机构不能为空");
			}
			if(StringUtilsV2.isBlank(flow.getFlowType())) {
				return ApiResult.error("流程对应业务模板不能为空");
			}
			if(StringUtilsV2.isBlank(flow.getFlowAttribute())) {
				return ApiResult.error("流程类型不能为空");
			}
			flow.setStatus(DataStatusType.STOP.getCode());
			return add(flow);
		}
		return edit(flow);
	}

	private ApiResult<?> add(FlowDesign flow){
		flow.setIsUsed("0");
		flowDao.save(flow);
		FlowDesignTemp temp = new FlowDesignTemp();
		temp.setFlowId(flow.getFlowId());
		temp.setFlowCode(flow.getFlowCode());
		temp.setFlowName(flow.getFlowName());
		temp.setFlowRemarks(flow.getFlowRemarks());
		temp.setEditLog("创建流程");
		temp.setIsUsed(flow.getIsUsed());
		temp.setCreateUserId(flow.getCreateUserId());
		flowTempDao.save(temp);
		return ApiResult.data(flow.getFlowId());
	}
	
	@Transactional
	public ApiResult<?> edit(FlowDesign flow){
		FlowDesign localflow = flowDao.getById(flow.getFlowId());
    	if(localflow != null) {
    		LoginUser user = UserUtil.getLoginUser();
    		if(!"0".equals(localflow.getFlowAttribute()) && !Constant.PLATFORM_ORG_ID.equals(user.getOrgId()) ){
				return ApiResult.error("非平台机构不能操作（保存/修改）'订制'或者'通用'流程");
			}
			StringBuffer sb = new StringBuffer("更新流程: ");
			boolean edit = false;
			int i = 0;
			if(StringUtilsV2.isNotBlank(flow.getFlowCode()) && !flow.getFlowCode().equals(localflow.getFlowCode())) {
				i++;
				sb.append("<br/>").append(i).append(".更新了流程编码.");
				edit = true;
			}
			if(StringUtilsV2.isNotBlank(flow.getFlowName()) && !flow.getFlowCode().equals(localflow.getFlowCode())) {
				i++;
				sb.append("<br/>").append(i).append(".更新了流程名称.");
				edit = true;
			}
			if(StringUtilsV2.isNotBlank(flow.getFlowRemarks()) && !flow.getFlowRemarks().equals(localflow.getFlowRemarks())) {
				i++;
				sb.append("<br/>").append(i).append(".更新了流程说明.");
				edit = true;
			}
			String flowData = flow.getFlowData();
			if(StringUtilsV2.isNotBlank(flowData)) {
				//设计数据格式完整且没有其他被启用的流程时，该流程默认状态为启用状态
				ApiResult<?> ar = flowCheck(null,flowData);
				if(ar.isSuccess()) {
					List<FlowDesign> list = flowDao.getByOrgIdAndStatusAndAttribute(localflow.getFollowOrgId(),localflow.getFlowType(), Constant.DATA_STATUS_TYPE_NORMAL, localflow.getFlowAttribute());
					if(list.size() == 0 || (list.size() == 1 && list.get(0).getFlowId().equals(flow.getFlowId()))) {
						//flowDao.updateStatus(Arrays.asList(flow.getFlowId()),DataStatusType.NORMAL.getCode());
						flow.setStatus(DataStatusType.NORMAL.getCode());
					}else {
						flow.setStatus(DataStatusType.STOP.getCode());
					}
				}else {
					flow.setStatus(DataStatusType.STOP.getCode());
				}
				flowDao.update(flow);
				FlowDesign editflow = flowDao.getById(flow.getFlowId());
				//JSONObject jsonObject1 = JSONObject.parseObject(flowData);
		        //JSONObject jsonObject2 = JSONObject.parseObject(localflow.getFlowData());
		        //System.out.println(jsonObject1.toJSONString());
		        //System.out.println(jsonObject2.toJSONString());
				//System.out.println(editflow.getFlowData());
		        //System.out.println(localflow.getFlowData());
				if(!editflow.getFlowData().equals(localflow.getFlowData())) {
					i++;
					sb.append("<br/>"+i+".更新了流程设计.");
					edit = true;
				}
			}else {
				flowDao.update(flow);
			}
			if(edit) {
				user = UserUtil.getLoginUser();
				FlowDesignTemp temp = new FlowDesignTemp();
				temp.setFlowId(flow.getFlowId());
				temp.setFlowCode(flow.getFlowCode());
				temp.setFlowName(flow.getFlowName());
				temp.setFlowRemarks(flow.getFlowRemarks());
				temp.setFlowData(flow.getFlowData());
				if(i != 1) {
					temp.setEditLog(sb.toString());
				}else {
					temp.setEditLog(sb.toString().replace("<br/>1.", ""));
				}
				
				temp.setCreateUserId(user.getUserId());
				flowTempDao.save(temp);
			}
			/*String currNodeId = "1566803746760";
			log.debug("1.流程设计格式验证:{}",flowCheck(null,flow.getFlowData()).toString());
			log.debug("2.获取指定节点id的节点，指定id传入空则返回开始节点:{}",getNode(null,flow.getFlowData(),currNodeId).toString());
			log.debug("3.获取指定节点id的下级节点id，指定节点id传入空则返回开始节点的下级节点ID: {}",firstOrLastNodeId(null,flow.getFlowData(),currNodeId,1).toString());
			log.debug("4.获取指定id的下级节点，指定id传入空则返回开始节点的下级节点:{}",firstOrLastNode(null,flow.getFlowData(),currNodeId,1).toString());
			log.debug("5.获取指定节点id的上级节点id，指定节点id传入空则返回开始节点的上级节点ID: {}",firstOrLastNodeId(null,flow.getFlowData(),currNodeId,0).toString());
			log.debug("6.获取指定id的上级节点，指定id传入空则返回开始节点的上级节点:{}",firstOrLastNode(null,flow.getFlowData(),currNodeId,0).toString());
			log.debug("7.某个节点是否是结束节点:{}",nodeIsEnd(null,flow.getFlowData(),null,currNodeId).toString());*/
    	}else {
    		return ApiResult.error("未找到流程");
    	}
    	return ApiResult.data(flow.getFlowId());
	}
	
	@Transactional
	public ApiResult<?> delete(String id) {
		LoginUser user = UserUtil.getLoginUser();

		FlowDesign flow =flowDao.getById(id);
    	if(flow != null) {
    		if(!"0".equals(flow.getFlowAttribute()) && !Constant.PLATFORM_ORG_ID.equals(user.getOrgId())){
				return ApiResult.error("非平台机构不能操作删除'订制'或者'通用'流程");
			}
			flowDao.updateStatus(Arrays.asList(id), DataStatusType.DELETE.getCode());
			FlowDesignTemp temp = new FlowDesignTemp();
			temp.setFlowId(flow.getFlowId());
			temp.setFlowCode(flow.getFlowCode());
			temp.setFlowName(flow.getFlowName());
			temp.setFlowRemarks(flow.getFlowRemarks());
			temp.setFlowData(flow.getFlowData());
			temp.setEditLog(DataStatusType.DELETE.getName()+"流程");
			temp.setCreateUserId(user.getUserId());
			flowTempDao.save(temp);
    	}else {
    		return ApiResult.error("未找到流程");
    	}
		return ApiResult.ok();
	}
	
	/**
	*  流程设计格式验证
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @return
	 */
	public ApiResult<?> flowCheck(JSONObject flow,String flowData) {	
		int beginCount = 0;
		int endCount = 0;
		int taskCount = 0;
		if((flow == null || flow.isEmpty()) && StringUtilsV2.isNotBlank(flowData)) {
			if(JSONUtils.mayBeJSON(flowData)) {
				flow = JSONObject.parseObject(flowData);
			}else {
				return ApiResult.error("流程设计数据不是JSON格式");
			}
		}
		if(flow == null || flow.isEmpty()) {
			return ApiResult.error("流程设计数据不能为空");
		}
		String title = "";
		if(flow != null) {
			title = flow.getString("title");
			if(StringUtilsV2.isBlank(title)) {
				return ApiResult.error("流程名称不能为空");
			}
			JSONObject nodes = flow.getJSONObject("nodes");
			if(nodes == null || nodes.isEmpty()) {
				return ApiResult.error("流程("+title+")节点数据不能为空");
			}else {
				Set<String> keys = nodes.keySet();
				for (String key : keys) {
					JSONObject node = nodes.getJSONObject(key);
					if(StringUtilsV2.isBlank(node.getString("name"))) {
						return ApiResult.error("流程("+title+")节点("+key+")名称不能为空");
					}
					if("start round mix".equals(node.getString("type"))) {
						if(upOrDownNodeId(flow,null,key,0).isSuccess()) {
							return ApiResult.error("流程("+title+")开始节点("+node.getString("name")+")之前不能再有其他上级节点存在");
						}
						beginCount++;
					} else if("end round mix".equals(node.getString("type"))) {
						if(upOrDownNodeId(flow,null,key,1).isSuccess()) {
							return ApiResult.error("流程("+title+")结束节点("+node.getString("name")+")之后不能再有其他下级节点存在");
						}
						endCount++;
					} else if("task".equals(node.getString("type"))) {
						taskCount++;
						if(StringUtilsV2.isBlank(node.getString("verifyModelIds"))) {
							return ApiResult.error("流程("+title+")节点("+node.getString("name")+")任务归属者不能为空");
						}
					}
				}
			}
			JSONObject lines = flow.getJSONObject("lines");
			if(lines != null && lines.isEmpty()) {
				return ApiResult.error("流程("+title+")必须将每个节点用(节点连线)连线连接起来");
			}
		}
		if(beginCount == 0) {
			return ApiResult.error("流程("+title+")必须要有一个开始节点");
		}else if(beginCount > 1){
			return ApiResult.error("流程("+title+")只能有一个开始节点");
		}
		if(endCount == 0) {
			return ApiResult.error("流程("+title+")必须要有一个结束节点");
		}else if(endCount > 1){
			return ApiResult.error("流程("+title+")只能有一个结束节点");
		}
		if(taskCount == 0) {
			return ApiResult.error("流程("+title+")必须要有一个任务节点");
		}
		if(taskCount == 0) {
			return ApiResult.error("流程("+title+")必须要有一个任务节点");
		}
		return ApiResult.ok();
	}
	/**
	 * 获取指定节点id的节点，指定id传入空则返回开始节点
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param currNodeId 指定节点id
	 * @return
	 */
	public ApiResult<JSONObject> getNode(JSONObject flow,String flowData,String currNodeId) {
		ApiResult<JSONObject> result = new ApiResult<JSONObject>();
		if((flow == null || flow.isEmpty()) && StringUtilsV2.isNotBlank(flowData)) {
			if(JSONUtils.mayBeJSON(flowData)) {
				flow = JSONObject.parseObject(flowData);
			}else {
				result.setMsg("流程设计内容格式不是JSON格式");
				result.setCode("500");
				result.setStatusCode("1");
				return result;
			}
		}
		if(flow == null || flow.isEmpty()) {
			result.setMsg("流程设计不能为空");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		JSONObject nodes = flow.getJSONObject("nodes");
		JSONObject node = null;
		if(nodes != null && !nodes.isEmpty()) {
			if(StringUtilsV2.isNotBlank(currNodeId)) {
				node = nodes.getJSONObject(currNodeId);
			}else {
				Set<String> keys = nodes.keySet();
				for (String key : keys) {
					node = nodes.getJSONObject(key);
					if(StringUtilsV2.isBlank(currNodeId) && node.getString("type").equals("start round mix")) {
						currNodeId = key;
						break;
					}
					node = null;
				}
			}
		}
		if(node == null) {
			result.setMsg("在流程("+flow.getString("title")+")中未找到"+(StringUtilsV2.isNotBlank(currNodeId)?"当前":"开始")+"节点");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		result.setData(node);
		result.setMsg(currNodeId);
		return result;
	}
	
	/**
	 * 获取流程的开始或者结束节点
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param beginOrEnd 0 开始 1结束
	 * @return
	 */
	public ApiResult<JSONObject> getNodeBeginOrEnd(JSONObject flow,String flowData,int beginOrEnd) {
		ApiResult<JSONObject> result = new ApiResult<JSONObject>();
		if((flow == null || flow.isEmpty()) && StringUtilsV2.isNotBlank(flowData)) {
			if(JSONUtils.mayBeJSON(flowData)) {
				flow = JSONObject.parseObject(flowData);
			}else {
				result.setMsg("流程设计内容格式不是JSON格式");
				result.setCode("500");
				result.setStatusCode("1");
				return result;
			}
		}
		if(flow == null || flow.isEmpty()) {
			result.setMsg("流程设计不能为空");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		String currNodeId = null;
		JSONObject nodes = flow.getJSONObject("nodes");
		JSONObject node = null;
		if(nodes != null && !nodes.isEmpty()) {
			Set<String> keys = nodes.keySet();
			for (String key : keys) {
				node = nodes.getJSONObject(key);
				if(beginOrEnd == 0 && node.getString("type").equals("start round mix")) {
					currNodeId = key;
					break;
				}
				if(beginOrEnd == 1 && node.getString("type").equals("end round mix")) {
					currNodeId = key;
					break;
				}
				node = null;
			}
			
		}
		if(node == null) {
			result.setMsg("在流程("+flow.getString("title")+")中未找到"+(beginOrEnd == 0?"开始":"结束")+"节点");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		result.setData(node);
		result.setMsg(currNodeId);
		return result;
	}
	
	/**
	 * 获取指定节点id的上/下级节点id，指定节点id传入空则返回开始节点的上/下级节点id
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param currNodeId 指定节点id
	 * @param firstOrLast 0上一个 1下一个
	 * @return
	 */
	public ApiResult<?> upOrDownNodeId(JSONObject flow,String flowData,String currNodeId,int firstOrLast) {
		if((flow == null || flow.isEmpty()) && StringUtilsV2.isNotBlank(flowData)) {
			if(JSONUtils.mayBeJSON(flowData)) {
				flow = JSONObject.parseObject(flowData);
			}else {
				return ApiResult.error("流程设计内容不是JSON格式");
			}
		}
		if(flow == null || flow.isEmpty()) {
			return ApiResult.error("流程设计不能为空");
		}
		ApiResult<JSONObject> ar = getNode(flow, flowData, currNodeId);
		if(!ar.isSuccess()) {
			return ar;
		}
		JSONObject node = ar.getData();
		currNodeId = ar.getMsg();
		JSONObject lines = flow.getJSONObject("lines");
		JSONObject line = null;
		String nodeId = null;
		if(lines != null && !lines.isEmpty()) {
			Set<String> keys = lines.keySet();
			for (String key : keys) {
				if(key.contains("-line")) {
					continue;
				}
				line = lines.getJSONObject(key);
				if(StringUtilsV2.isNotBlank(currNodeId)) {
					if(firstOrLast == 0 && currNodeId.equals(line.getString("to"))) {
						nodeId = line.getString("from");
						break;
					}else if(firstOrLast == 1 && currNodeId.equals(line.getString("from"))) {
						nodeId = line.getString("to");
						break;
					}
				}
			}
		}
		if(nodeId == null) {
			return ApiResult.error("在流程("+flow.getString("title")+")中未找到节点("+node.getString("name")+")对应的"+(firstOrLast == 0?"上":"下")+"一个任务节点");
		}
		return ApiResult.data(nodeId);
	}
	
	/**
	 * 获取指定id的上/下级节点，指定id传入空则返回开始节点的上/下级节点
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param currNodeId 指定节点id
	 * @param firstOrLast 0上一个 1下一个
	 * @return
	 */
	public ApiResult<JSONObject> upOrDownNode(JSONObject flow,String flowData,String currNodeId,int firstOrLast) {
		ApiResult<JSONObject> result = new ApiResult<JSONObject>();
		ApiResult<?> ar = upOrDownNodeId( flow, flowData, currNodeId,firstOrLast);
		if(!ar.isSuccess()) {
			result.setMsg(ar.getMsg());
			result.setCode(ar.getCode());
			result.setStatusCode(ar.getStatusCode());
			return result;
		}
		String ntNodeId = ar.getData().toString();
		return getNode(flow, flowData, ntNodeId);
	}
	
	/**
	 * 某个节点是否是结束节点
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param node 指定节点
	 * @param currNodeId 指定节点id
	 * @return
	 */
	public ApiResult<Boolean> nodeIsEnd(JSONObject flow,String flowData,JSONObject node,String currNodeId) {
		ApiResult<Boolean> result = new ApiResult<Boolean>();
		if(node == null) {
			ApiResult<JSONObject> ar = getNode(flow, flowData, currNodeId);
			if(!ar.isSuccess()) {
				result.setMsg(ar.getMsg());
				result.setCode(ar.getCode());
				result.setStatusCode(ar.getStatusCode());
				return result;
			}
			node = ar.getData();
		}
		if(node == null) {
			result.setMsg("未找到流程节点");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		result.setData("end round mix".equals(node.getString("type")));
		return result;
	}
	
	/**
	 * 某个节点的下一个节点是否是结束节点
	 * @param flow 流程json对象
	 * @param flowData 流程json字符串
	 * @param currNodeId 指定节点id
	 * @return
	 */
	public ApiResult<Boolean> nodeNextNodeIsEnd(JSONObject flow,String flowData,String currNodeId) {
		ApiResult<Boolean> result = new ApiResult<Boolean>();
		ApiResult<JSONObject> ar = upOrDownNode(flow, flowData, currNodeId,1);
		if(!ar.isSuccess()) {
			result.setMsg(ar.getMsg());
			result.setCode(ar.getCode());
			result.setStatusCode(ar.getStatusCode());
			return result;
		}
		JSONObject node = ar.getData();
		if(node == null) {
			result.setMsg("未找到下一个流程节点");
			result.setCode("500");
			result.setStatusCode("1");
			return result;
		}
		result.setData("end round mix".equals(node.getString("type")));
		return result;
	}
	

	public FlowDesignTemp getTempByFlowId(String flowId) {
		return flowTempDao.getByFlowId(flowId);
	}
	
	public FlowDesignTemp getTempById(String flowTempId) {
		return flowTempDao.getById(flowTempId);
	}

}
